use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::time::Duration;

use lazy_static::lazy_static;
use log::info;
use moka::sync::Cache;

use common::error::MyError;

use crate::jwt;
use crate::jwt::Claims;
use crate::state::{ApiAuthConfModel, AuthState, TokenAuthModel};

lazy_static! {
    static ref AUTH_CACHE: Arc<RwLock<AuthState>> = Arc::new(RwLock::new(AuthState {
        token_uid_cache: Cache::builder()
            .time_to_live(Duration::from_secs(120 * 60))
            .build(),
        uid_token_cache: Cache::builder()
            .time_to_live(Duration::from_secs(120 * 60))
            .build(),
        captcha_key: Cache::builder()
            .time_to_live(Duration::from_secs(3 * 60))
            .build(),
        auth_conf: None,
        token_auth_cache: HashMap::new(),
    }));
}

pub fn get_auth_state_read() -> Result<RwLockReadGuard<'static, AuthState>, MyError> {
    Ok(AUTH_CACHE.read().unwrap())
}

pub fn get_auth_state_write() -> Result<RwLockWriteGuard<'static, AuthState>, MyError> {
    Ok(AUTH_CACHE.write().unwrap())
}

pub fn set_auth_conf(conf: Option<ApiAuthConfModel>) -> Result<(), MyError> {
    match conf {
        None => Err(MyError::ServerError("auth_conf is empty".to_string())),
        Some(conf) => {
            let mut auth_cache = get_auth_state_write()?;
            auth_cache.auth_conf = Some(Arc::new(conf.clone()));
            Ok(())
        }
    }
}

pub fn get_auth_conf() -> Result<Arc<ApiAuthConfModel>, MyError> {
    let auth_cache = get_auth_state_read()?;
    match &auth_cache.auth_conf {
        None => Err(MyError::ServerError("auth_conf is empty".to_string())),
        Some(auth_conf) => Ok(Arc::clone(auth_conf)),
    }
}

pub fn save_token_auth(
    uid: i64,
    user_name: String,
    token_auth_model: TokenAuthModel,
) -> Result<String, MyError> {
    info!(
        ">>>>>>>>>> [{}],[{}]生成鉴权信息 <<<<<<<<<<",
        uid, user_name
    );
    let token = jwt::gen_jwt_token(user_name, uid)?;
    let mut auth_cache = get_auth_state_write()?;
    auth_cache.uid_token_cache.insert(uid, token.clone());
    auth_cache.token_uid_cache.insert(token.clone(), uid);
    auth_cache
        .token_auth_cache
        .insert(token.clone(), token_auth_model);
    Ok(token)
}

pub fn get_token_auth_cache(token: &str) -> Result<TokenAuthModel, MyError> {
    let auth_cache = get_auth_state_read()?;
    Ok(auth_cache
        .token_auth_cache
        .get(token)
        .ok_or(MyError::UnauthorizedError("授权凭证过期".to_string()))?
        .clone())
}

pub fn get_uid_by_token(token: &str) -> Result<i64, MyError> {
    let auth_cache = get_auth_state_read()?;
    Ok(auth_cache
        .token_auth_cache
        .get(token)
        .ok_or(MyError::UnauthorizedError("授权凭证过期".to_string()))?
        .uid)
}

pub fn validation_token(token: &str) -> Result<Claims, MyError> {
    get_token_auth_cache(token)?;
    Ok(jwt::validation_jwt_token(token)?)
}

pub fn destroy_token(token: &str) -> Result<bool, MyError> {
    info!(">>>>>>>>>> 注销鉴权信息 <<<<<<<<<<");
    let mut auth_cache = get_auth_state_write()?;
    auth_cache.destroy_token(token);
    Ok(true)
}

pub fn destroy_token_by_uid(uid: &i64) -> Result<bool, MyError> {
    info!(">>>>>>>>>> [{}]注销鉴权信息 <<<<<<<<<<", uid);
    let mut auth_state = get_auth_state_write()?;
    auth_state.destroy_token_by_uid(uid);
    Ok(true)
}
